// import QUIWidget from "./QUIWidget";
import { QUIView, QUIViewConfig } from "./QUIView";
import { QUILabel, QUILabelConfig } from "./QUILabel";
import { QUIScrollArea, QUIScrollAreaConfig } from "./QUIScrollArea";
import {
    QUIVerticalLayout,
    QUIVerticalLayoutConfig,
} from "./QUIVerticalLayout";

import { QUIGridLayout, QUIGridConfig } from "./QUIGridLayout";

import {
    QUIHorizontalLayout,
    QUIHorizontalLayoutConfig,
} from "./QUIHorizontalLayout";

import { QUIButton, QUIButtonConfig } from "./QUIButton";
import { QUIInput, QUIInputConfig } from "./QUIInput";
import { QUIComboBox, QUIComboBoxConfig } from "./QUIComboBox";

import QGameInstantiateObject from "./QGameInstantiateObject";
import JSZip from "jszip";

declare global {
    namespace Phaser {
        interface Scene {
            // rexUI: RexUIPlugin;
            qGame: QGamePlugin;
        }
    }
}

interface QProjectInfo {
    images: string[];
    view: string[];
    [key: string]: any;
}

class QPackageFile extends Phaser.Loader.File {
    public data: object = {};
    public projectInfo: QProjectInfo = { images: [], view: [] };

    constructor(loader: Phaser.Loader.LoaderPlugin, key: string, url: string) {
        super(loader, {
            type: "qgp",
            key: key,
            url: url,
            responseType: "arraybuffer",
        });
    }

    private async addZipResource(
        file: JSZip.JSZipObject,
        path: string
    ): Promise<void> {
        const extension = path.split(".").pop()?.toLowerCase() || "";
        const fileName = path.split("/").pop() || path;
        const blob = await file.async("blob");
        const blobUrl = URL.createObjectURL(blob);

        let key = path;
        switch (extension) {
            case "png":
            case "jpg":
            case "jpeg":
            case "webp":
                this.loader.image(key, blobUrl);
                this.projectInfo["images"].push(key);
                break;
            // case "json":
            //     this.loader.json(path, blobUrl);
            //     break;
            case "mp3":
            case "ogg":
            case "xml":
                const name = fileName.split(".").slice(0, -1).join(".");
                key = this.key + "_" + name;
                this.loader.xml(key, blobUrl);
                this.projectInfo["view"].push(key);
                break;
            case "atlas":
                break;
        }

        // 资源加载完成后释放Blob URL
        this.loader.once(`filecomplete`, (skey: string) => {
            if (skey === key) {
                // console.log("filecomplete aa", fileName);
                URL.revokeObjectURL(blobUrl);
            }
        });
    }

    async onLoad(data: any) {
        if (data.status !== 200) {
            this.state = Phaser.Loader.FILE_ERRORED;
            if (!this.projectInfo.view) this.projectInfo.view = [];
            if (!this.projectInfo.images) this.projectInfo.images = [];
            this.state = Phaser.Loader.FILE_ERRORED;
            this.loader.nextFile(this, false);
            return;
        }
        const zip = await JSZip.loadAsync(data.response);
        const jsonstr = await zip.files["project.json"].async("text");
        this.projectInfo = JSON.parse(jsonstr);
        this.projectInfo["view"] = [];
        this.projectInfo["images"] = [];

        zip.remove("project.json");
        // console.log(this.projectInfo);
        for (const [relativePath, file] of Object.entries(zip.files)) {
            if (!file.dir) {
                await this.addZipResource(file, relativePath);
            }
        }
        this.state = Phaser.Loader.FILE_COMPLETE;
        this.pendingDestroy();
        const infostr = JSON.stringify(this.projectInfo);
        QGamePlugin.qPackageTable[this.key] = JSON.parse(infostr);
        // this.data["projectInfo"] = this.projectInfo;
        this.loader.nextFile(this, false);
    }
}

Phaser.Loader.FileTypesManager.register(
    "qpackage",
    function (this: Phaser.Loader.LoaderPlugin, key: string, url: string) {
        this.addFile(new QPackageFile(this, key, url));
        return this;
    }
);

class QGameUIFactory {
    private manger: QGamePlugin | null = null;
    private scene: Phaser.Scene | null = null;
    private viewList: Array<QUIView> = [];

    constructor() {}
    init(scene: Phaser.Scene, manger: QGamePlugin) {
        this.scene = scene;
        this.manger = manger;
    }

    get Nodes(): Array<QUIView> {
        return this.viewList;
    }

    pushNode(view: QUIView) {
        this.viewList.push(view);
    }

    removeNode(view: QUIView) {
        const index = this.viewList.indexOf(view);
        if (index != -1) {
            this.viewList.splice(index, 1);
        }
    }

    createView(key: string): QUIView | null {
        if (this.scene === null) return null;
        if (this.manger === null) return null;
        const xml = this.scene.cache.xml.get(key);
        if (!xml) {
            console.error(`view file not found: ${key}`);
            return null;
        }
        // console.log(xml);
        const o = new QGameInstantiateObject(this.scene, this.manger);
        const xmlString = new XMLSerializer().serializeToString(xml);
        const view = o.parse(xmlString);
        return view;
    }

    objectFromXML(xmlString: string): QUIView | null {
        if (this.scene === null) return null;
        if (this.manger === null) return null;
        const o = new QGameInstantiateObject(this.scene, this.manger);
        const view = o.parse(xmlString);
        return view;
    }

    verticalLayout(config?: QUIVerticalLayoutConfig) {
        if (this.scene === null) return null;
        if (this.manger === null) return null;
        const o = new QUIVerticalLayout(this.scene, this.manger, config);
        this.viewList.push(o);
        return o;
    }

    horizontalLayout(config?: QUIHorizontalLayoutConfig) {
        if (this.scene === null) return null;
        if (this.manger === null) return null;
        const o = new QUIHorizontalLayout(this.scene, this.manger, config);
        this.viewList.push(o);
        return o;
    }
    gridLayout(config?: QUIGridConfig) {
        if (this.scene === null) return null;
        if (this.manger === null) return null;
        const o = new QUIGridLayout(this.scene, this.manger, config);
        this.viewList.push(o);
        return o;
    }

    view(config?: QUIViewConfig): QUIView | null {
        if (this.scene === null) return null;
        if (this.manger === null) return null;
        const o = new QUIView(this.scene, this.manger, config);
        this.viewList.push(o);
        return o;
    }

    scroll(config?: QUIScrollAreaConfig): QUIScrollArea | null {
        if (this.scene === null) return null;
        if (this.manger === null) return null;
        const o = new QUIScrollArea(this.scene, this.manger, config);
        this.viewList.push(o);
        return o;
    }

    label(config?: QUILabelConfig): QUILabel | null {
        if (this.scene === null) return null;
        if (this.manger === null) return null;
        const o = new QUILabel(this.scene, this.manger, config);
        this.viewList.push(o);
        return o;
    }

    button(config?: QUIButtonConfig): QUIButton | null {
        if (this.scene === null) return null;
        if (this.manger === null) return null;
        const o = new QUIButton(this.scene, this.manger, config);
        this.viewList.push(o);
        return o;
    }

    input(config?: QUIInputConfig): QUIInput | null {
        if (this.scene === null) return null;
        if (this.manger === null) return null;
        const o = new QUIInput(this.scene, this.manger, config);
        this.viewList.push(o);
        return o;
    }

    comboBox(config?: QUIComboBoxConfig): QUIComboBox | null {
        if (this.scene === null) return null;
        if (this.manger === null) return null;
        const o = new QUIComboBox(this.scene, this.manger, config);
        this.viewList.push(o);
        return o;
    }
}

class QGamePlugin extends Phaser.Plugins.ScenePlugin {
    public add: QGameUIFactory = new QGameUIFactory();

    public static qPackageTable: { [key: string]: any } = {};

    constructor(
        scene: Phaser.Scene,
        pluginManager: Phaser.Plugins.PluginManager,
        pluginKey: string
    ) {
        super(scene, pluginManager, pluginKey);

        // 确保场景启动后初始化
        if (!scene.sys.settings.isBooted) {
            scene.sys.events.once("boot", this.boot, this);
        }
    }

    boot() {
        if (this.systems) {
            const eventEmitter = this.systems.events;
            // 添加销毁钩子
            eventEmitter.once("destroy", this.destroy, this);
            if (this.scene) {
                this.add.init(this.scene, this);
            }
        }
    }
    getImageKey(url: string): string {
        // return this.scene.textures.getBaseURL();
        return "";
    }

    private getXMLResourceUrls(node: Element, urls: string[] = []) {
        const url = node.getAttribute("imageUrl");
        if (url) {
            urls.push(url);
        }
        Array.from(node.children).forEach((childNode) => {
            this.getXMLResourceUrls(childNode, urls);
        });
    }

    loadXML(key: string, url: string, callback?: Function) {
        if (this.scene) {
            this.scene.load.once(
                "filecomplete",
                (ckey: string, type: string, xmlData: any) => {
                    if (this.scene && key == ckey) {
                        const rootNode = xmlData.documentElement;
                        const urls: any[] | undefined = [];
                        this.getXMLResourceUrls(rootNode, urls);

                        this.scene.load.reset();
                        urls.forEach((url) => {
                            if (this.scene) {
                                this.scene.load.image(url, url);
                            }
                        });
                        this.scene.load.start();
                        if (callback) {
                            callback(key, url, xmlData);
                        }
                    }
                },
                this
            );
            this.scene.load.xml(key, url);
        }
    }

    loadQPackage(key: string, url: string) {
        if (this.scene) {
            this.scene.load.on(
                "filecomplete",
                (ckey: string, type: string, file: QPackageFile) => {
                    if (key === ckey) {
                        console.log(ckey, "success");
                        // console.log(QGamePlugin.qPackageTable);
                    }
                }
            );

            this.scene.load.addFile(
                new QPackageFile(this.scene.load, key, url)
            );
        }
    }

    public getPackageInfo() {
        return QGamePlugin.qPackageTable;
    }

    public findViewById(id: string): QUIView | null {
        if (this.add == null) return null;
        for (let i = 0; i < this.add.Nodes.length; i++) {
            const view = this.add.Nodes[i];
            if (view.Id == id) {
                return view;
            }
        }
        return null;
    }

    public findViewByClass(className: string): QUIView[] {
        const ret: QUIView[] = [];
        if (this.add == null) return ret;
        for (let i = 0; i < this.add.Nodes.length; i++) {
            const view = this.add.Nodes[i];
            if (view.Class == className) {
                ret.push(view);
            }
        }
        return ret;
    }

    public findViewByName(name: string): QUIView[] {
        const ret: QUIView[] = [];
        if (this.add == null) return ret;
        for (let i = 0; i < this.add.Nodes.length; i++) {
            const view = this.add.Nodes[i];
            if (view.Name == name) {
                ret.push(view);
            }
        }
        return ret;
    }

    public findViewByUUID(uuid: string): QUIView | null {
        if (this.add == null) return null;
        for (let i = 0; i < this.add.Nodes.length; i++) {
            const view = this.add.Nodes[i];
            if (view.UUID == uuid) {
                return view;
            }
        }
        return null;
    }

    public positionFindView(
        x: number,
        y: number,
        filter: QUIView[] = []
    ): QUIView | null {
        let retView: QUIView | null = null;
        if (this.add == null) return null;
        for (let i = this.add.Nodes.length; i >= 0; i--) {
            const view = this.add.Nodes[i];
            if (view === undefined) {
                continue;
            }
            // console.log(view);
            const matrix = view.Container.getWorldTransformMatrix();
            const vx = matrix.getX(0, 0);
            const vy = matrix.getY(0, 0);
            if (
                x > vx &&
                x < vx + view.Width &&
                y > vy &&
                y < vy + view.Height
            ) {
                if (filter.indexOf(view) == -1) {
                    retView = view;
                    break;
                }
            }
        }
        return retView;
    }

    destroy() {
        console.log("qgameplugin destroy");
        // this.scene = undefined;
    }
}

export default QGamePlugin;
export {
    QGamePlugin,
    QUIButton,
    QUIButtonConfig,
    QUIView,
    QUIViewConfig,
    QUIInput,
    QUIInputConfig,
    QUILabel,
    QUILabelConfig,
    QUIGridLayout,
    QUIGridConfig,
    QUIComboBox,
    QUIComboBoxConfig,
    QUIScrollArea,
    QUIScrollAreaConfig,
    QUIHorizontalLayout,
    QUIHorizontalLayoutConfig,
    QUIVerticalLayout,
    QUIVerticalLayoutConfig,
};
